<template><div><h2 id="hello-world" tabindex="-1"><a class="header-anchor" href="#hello-world"><span>Hello world</span></a></h2>
<p>本章描述了如何在你的应用中创建一个新的 “Hello world” 页面。为了实现这一目标，将会创建一个 <a href="https://learnku.com/docs/yii-framework/2.0.x/controller/12002#77aa4c" target="_blank" rel="noopener noreferrer">动作</a> 和一个 <a href="https://learnku.com/docs/yii-framework/2.0.x/views/12005#e5a2b2" target="_blank" rel="noopener noreferrer">视图</a> ：</p>
<ul>
<li>应用将会分派页面请求给动作</li>
<li>动作将会依次渲染视图呈现 “Hello world” 给最终用户</li>
</ul>
<p>贯穿整个章节，你将会掌握三件事：</p>
<ol>
<li>如何创建一个动作去响应请求，</li>
<li>如何创建一个视图去构造响应内容，</li>
<li>以及一个应用如何分派请求给动作。</li>
</ol>
<h2 id="创建动作" tabindex="-1"><a class="header-anchor" href="#创建动作"><span>创建动作</span></a></h2>
<p>为了 “Hello world”，需要创建一个 <code v-pre>say</code> 动作，从请求中接收 <code v-pre>message</code> 参数并显示给最终用户。如果请求没有提供 <code v-pre>message</code> 参数，操作将显示默认参数 “Hello”。</p>
<blockquote>
<p>Info: 动作是最终用户可以直接访问并执行的对象，它被组织在 <a href="https://learnku.com/docs/yii-framework/2.0.x/controller/12002" target="_blank" rel="noopener noreferrer">控制器</a> 中。一个动作的执行结果就是最终用户收到的响应内容。动作必须声明在控制器中。为了简单起见，你可以直接在 <code v-pre>SiteController</code> 控制器里声明 <code v-pre>say</code> 动作。这个控制器是由文件 <code v-pre>controllers/SiteController.php</code> 定义的。以下是一个动作的声明：</p>
</blockquote>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">app<span class="token punctuation">\</span>controllers</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>web<span class="token punctuation">\</span>Controller</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">SiteController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span><span class="token punctuation">{</span></span>
<span class="line">     <span class="token comment">// ...现存的代码...</span></span>
<span class="line">    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">actionSay</span><span class="token punctuation">(</span><span class="token variable">$message</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'Hello'</span><span class="token punctuation">)</span></span>
<span class="line">    <span class="token punctuation">{</span></span>
<span class="line">         <span class="token keyword">return</span> <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">render</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'say'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string single-quoted-string">'message'</span> <span class="token operator">=></span> <span class="token variable">$message</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在上述 <code v-pre>SiteController</code> 代码中，<code v-pre>say</code> 动作被定义为 <code v-pre>actionSay</code> 方法。Yii 使用 <code v-pre>action</code> 前缀区分普通方法和动作。<code v-pre>action</code> 前缀后面的名称被映射为操作的 ID。</p>
<p>涉及到给操作命名时，你应该理解 Yii 如何处理操作 ID。操作 ID 总是被以小写处理，如果一个操作 ID 由多个单词组成，单词之间将由连字符连接（如 <code v-pre>create-comment</code>）。操作 ID 映射为方法名时移除了连字符，将每个单词首字母大写，并加上 <code v-pre>action</code> 前缀。例子：操作 ID <code v-pre>create-comment</code> 相当于方法名 <code v-pre>actionCreateComment</code>。</p>
<p>上述代码中的操作方法接受一个参数 <code v-pre>$message</code>，它的默认值是 <code v-pre>“Hello”</code>（就像你设置 PHP 中其它函数或方法的默认值一样）。当应用接收到请求并确定由 <code v-pre>say</code> 操作来响应请求时，应用将从请求的参数中寻找对应值传入进来。换句话说，如果请求包含一个 <code v-pre>message</code> 参数，它的值是 <code v-pre>“Goodbye”</code>， 操作方法中的 <code v-pre>$message</code> 变量也将被填充为 <code v-pre>“Goodbye”</code>。</p>
<p>在操作方法中，[[yii\web\Controller::render()|render()]] 被用来渲染一个<br>
名为 <code v-pre>say</code> 的视图文件。<code v-pre>message</code> 参数也被传入视图，这样就可以在里面使用。操作方法会返回渲染结果。结果会被应用接收并显示给最终用户的浏览器（作为整页 HTML 的一部分）。</p>
<h2 id="创建视图" tabindex="-1"><a class="header-anchor" href="#创建视图"><span>创建视图</span></a></h2>
<p>视图是你用来生成响应内容的脚本。为了说 “Hello”，你需要创建一个 <code v-pre>say</code> 视图，以便显示从操作方法中传来的 <code v-pre>message</code> 参数。</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">yii<span class="token punctuation">\</span>helpers<span class="token punctuation">\</span>Html</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token delimiter important">?></span></span></span>
<span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?=</span> <span class="token class-name static-context">Html</span><span class="token operator">::</span><span class="token function">encode</span><span class="token punctuation">(</span><span class="token variable">$message</span><span class="token punctuation">)</span> <span class="token delimiter important">?></span></span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><code v-pre>say</code> 视图应该存为 <code v-pre>views/site/say.php</code> 文件。当一个操作中调用了 [[yii\web\Controller::render()|render()]] 方法时，它将会按 <code v-pre>views/控制器 ID/视图名.php</code> 路径加载 PHP 文件。</p>
<p>注意以上代码，<code v-pre>message</code> 参数在输出之前被 [[yii\helpers\Html::encode()|HTML-encoded]] 方法处理过。这很有必要，当参数来自于最终用户时，参数中可能隐含的恶意 JavaScript 代码会导致 <a href="https://zh.wikipedia.org/wiki/%E8%B7%A8%E7%B6%B2%E7%AB%99%E6%8C%87%E4%BB%A4%E7%A2%BC" target="_blank" rel="noopener noreferrer">跨站脚本（XSS）</a> 攻击。</p>
<p>当然了，你大概会在 <code v-pre>say</code> 视图里放入更多内容。内容可以由 HTML 标签，纯文本，甚至 PHP 语句组成。实际上 <code v-pre>say</code> 视图就是一个由 [[yii\web\Controller::render()|render()]] 执行的 PHP 脚本。视图脚本输出的内容将会作为响应结果返回给应用。应用将依次输出结果给最终用户。</p>
<h2 id="试运行" tabindex="-1"><a class="header-anchor" href="#试运行"><span>试运行</span></a></h2>
<p>创建完动作和视图后，你就可以通过下面的 URL 访问新页面了：</p>
<div class="language-bash line-numbers-mode" data-highlighter="prismjs" data-ext="sh" data-title="sh"><pre v-pre class="language-bash"><code><span class="line">http://hostname/index.php?r<span class="token operator">=</span>site/say<span class="token operator">&amp;</span><span class="token assign-left variable">message</span><span class="token operator">=</span>Hello+World</span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div></div></div><p><img src="https://cdn.learnku.com/uploads/images/202201/29/93088/YyRbpfanx2.png!large" alt="Hello world"></p>
<p>这个 URL 将会输出包含 “Hello World” 的页面，页面和应用里的其它页面使用同样的头部和尾部。</p>
<p>如果你省略 URL 中的 <code v-pre>message</code> 参数，将会看到页面只显示 “Hello”。这是因为 <code v-pre>message</code> 被作为一个参数传给 <code v-pre>actionSay()</code> 方法，当省略它时，参数将使用默认的 <code v-pre>“Hello”</code> 代替。</p>
<blockquote>
<p>Info: 新页面和其它页面使用同样的头部和尾部是因为 [[yii\web\Controller::render()|render()]] 方法会自动把 <code v-pre>say</code> 视图执行的结果嵌入称为 <a href="https://learnku.com/docs/yii-framework/2.0.x/views/12005#5aefca" target="_blank" rel="noopener noreferrer">布局</a> 的文件中，本例中是 <code v-pre>views/layouts/main.php</code>。</p>
</blockquote>
<p>上面 URL 中的参数 <code v-pre>r</code> 需要更多解释。它代表 <a href="https://learnku.com/docs/yii-framework/2.0.x/hello-world/runtime-routing.md" target="_blank" rel="noopener noreferrer">路由</a>，是整个应用级的，指向特定操作的独立 ID。路由格式是 <code v-pre>控制器 ID/操作 ID</code>。应用接受请求的时候会检查参数，使用控制器 ID 去确定哪个控制器应该被用来处理请求。然后相应控制器将使用操作 ID 去确定哪个操作方法将被用来做具体工作。上述例子中，路由 <code v-pre>site/say</code> 将被解析至 <code v-pre>SiteController</code> 控制器和其中的 <code v-pre>say</code> 操作。因此 <code v-pre>SiteController::actionSay()</code> 方法将被调用处理请求。</p>
<blockquote>
<p>Info: 与操作一样，一个应用中控制器同样有唯一的 ID。控制器 ID 和操作 ID 使用同样的命名规则。控制器的类名源自于控制器 ID，移除了连字符，每个单词首字母大写，并加上 <code v-pre>Controller</code> 后缀。例如：控制器 ID <code v-pre>post-comment</code> 相当于控制器类名 <code v-pre>PostCommentController</code>。</p>
</blockquote>
<h2 id="总结" tabindex="-1"><a class="header-anchor" href="#总结"><span>总结</span></a></h2>
<p>通过本章节你接触了 MVC 设计模式中的控制器和视图部分。创建了一个操作作为控制器的一部分去处理特定请求。然后又创建了一个视图去构造响应内容。在这个小例子中，没有模型调用，唯一涉及到数据的地方是 <code v-pre>message</code> 参数。</p>
<p>你同样学习了 Yii 路由的相关内容，它是用户请求与控制器动作之间的桥梁。</p>
<p>在下一章节中，你将学习如何创建一个模型，以及添加一个包含 HTML 表单的页面。</p>
<blockquote>
<p>💖喜欢本文档的，欢迎点赞、收藏、留言或转发，谢谢支持！<br>
作者邮箱：zhuzixian520@126.com，github地址：<a href="https://github.com/zhuzixian520" target="_blank" rel="noopener noreferrer">github.com/zhuzixian520</a></p>
</blockquote>
</div></template>


